/*
 * lr-wpan-transactionList.cc
 *
 *  Created on: 19 févr. 2012
 *      Author: stephane
 */

#include "ns3/log.h"
#include "ns3/lr-wpan-transactionList.h"
#include "ns3/simulator.h"
#include "ns3/uinteger.h"


NS_LOG_COMPONENT_DEFINE("LrWpanTransactionList");




namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (LrWpanTransactionList);
 const uint8_t LrWpanTransactionList::max_transaction = 3;


TypeId
LrWpanTransactionList::GetTypeId(void)
{
  static TypeId tid = TypeId ("ns3::LrWpanTransactionList")
    		.SetParent<Object> ()
    		.AddConstructor<LrWpanTransactionList>();
 return tid;
}

LrWpanTransactionList::LrWpanTransactionList(void)
{

}
LrWpanTransactionList::~LrWpanTransactionList()
{

}

int
LrWpanTransactionList::search(Address add, LrWpanAddressMode addType)
{
	NS_ASSERT_MSG(((addType == EXT_ADDR)||(addType == SHORT_ADDR)),
			"the address mode is not a valid one");
	std::list<Ptr<Packet> >::iterator it;
	int found =  0;
	if(m_transactions.empty())
	{
		NS_LOG_ERROR("the transaction list is empty");
		return found;
	}
	if(addType == SHORT_ADDR)
	{
		Ptr<Packet> copyPKT;
		LrWpanMacHeader hdr;
		for(it = m_transactions.begin(); it != m_transactions.end(); it++)
		{
			copyPKT = (*it)->Copy();
			copyPKT->RemoveHeader(hdr);
			if(hdr.GetShortDstAddr() == Mac16Address::ConvertFrom(add))
			{
				found++;
			}
		}
		copyPKT = 0;
	}
	else
	{
		Ptr<Packet> copyPKT ;
		LrWpanMacHeader hdr;
		for(it = m_transactions.begin(); it != m_transactions.end(); it++)
		{
			copyPKT = (*it)->Copy();
			copyPKT->RemoveHeader(hdr);
			if(hdr.GetExtDstAddr() == Mac64Address::ConvertFrom(add))
			{
				found ++;
			}
		}
		copyPKT = 0;
	}
	return found;
}

Ptr<Packet>
LrWpanTransactionList::Update(Address add, LrWpanAddressMode addType)
{
	Ptr<Packet> pkt = get(add,addType);
	Ptr<Packet> returnPkt ;
	LrWpanMacHeader hdr;
	LrWpanMacTrailer trl;
	pkt->RemoveHeader(hdr);
	pkt->RemoveTrailer(trl);
	//todo complete with all case of indirect transmission
	if(hdr.IsCommand())
	{
		uint8_t cmdType;
		pkt->CopyData(&cmdType,1);
		switch (cmdType) {
			case 0x02:			//associate Response, we have 4 element into the buffer we copy them into the new packet
			{
				uint8_t buffer[4];
				pkt->CopyData(buffer,4);
				returnPkt = Create<Packet>(buffer,4);
				break;
			}

			default:
				NS_LOG_ERROR(this);
				break;
		}

	}
	hdr.SetFrmPend();			//we update the framepending field
	returnPkt->AddHeader(hdr);	//add the header to the new packet
	returnPkt->AddTrailer(trl);
	return returnPkt;

}
Ptr<Packet>
LrWpanTransactionList::get(Address add, LrWpanAddressMode addType)  //try to use the search only
{

	NS_ASSERT_MSG(((addType == EXT_ADDR)||(addType == SHORT_ADDR)),
				"the address mode is not a valid one");
		std::list<Ptr<Packet> >::iterator it;
		Ptr<Packet> returnPKT;
		if(m_transactions.empty())
		{
			NS_LOG_ERROR("the transaction list is empty");
			return 0;
		}
		if(addType == SHORT_ADDR)
		{
			for(it = m_transactions.begin(); it != m_transactions.end(); it++)
			{
				Ptr<Packet> copyPKT = (*it)->Copy();
				LrWpanMacHeader hdr;
				copyPKT->RemoveHeader(hdr);
				if(hdr.GetShortDstAddr() == Mac16Address::ConvertFrom(add))
				{
					copyPKT = 0;
					returnPKT = (*it)->Copy();
					(*it) = 0;								//we cancel the packet into the transaction
					m_transactions.erase(it);				//we cancel the transaction
					break;
				}
			}
		}
		else
		{
			for(it = m_transactions.begin(); it != m_transactions.end(); it++)
			{
				Ptr<Packet> copyPKT = (*it)->Copy();
				LrWpanMacHeader hdr;
				copyPKT->RemoveHeader(hdr);
				if(hdr.GetExtDstAddr() == Mac64Address::ConvertFrom(add))
				{
					copyPKT = 0;
					returnPKT = (*it)->Copy();
					(*it) = 0;						//we cancel the packet into the transaction
					m_transactions.erase(it);				//we cancel the transaction
					break;
				}
			}
		}
		return returnPKT;
}

void LrWpanTransactionList::add(Ptr<Packet> pkt)
{
	if(m_transactions.size() == max_transaction)
	{
		NS_LOG_ERROR("we cannot have more than " << max_transaction <<" transactions stored");
		return;
	}
	m_transactions.push_back(pkt->Copy());
}
bool LrWpanTransactionList::isfull() const
{
	return m_transactions.size() == max_transaction;
}
bool LrWpanTransactionList::isEmpty() const
{
	return m_transactions.empty();
}

void
LrWpanTransactionList::cancelTransaction()
{
	NS_ASSERT_MSG(!isEmpty(),"The TransactionList is empty, Nothing to cancel");
	m_transactions.front() = 0;;
	m_transactions.pop_front();
}

void
LrWpanTransactionList::setMac(Ptr<LrWpanMac> mac)
{
	m_mac = mac;
}
void
LrWpanTransactionList::DoDispose(void)
{
	m_mac = 0;
	std::list<Ptr<Packet> >::iterator it;
	for(it = m_transactions.begin();it != m_transactions.end();it++)
	{
		(*it) = 0;
	}
	m_transactions.clear();
}
}  // namespace ns3
